home *** CD-ROM | disk | FTP | other *** search
- /*
- ** Apple Macintosh Developer Technical Support
- **
- ** Routines demonstrating how to play QDesign compressed AIFF files
- ** using a combination of QuickTime and the Sound Manager.
- **
- ** by Mark Cookson, Apple Developer Technical Support
- **
- ** File: QDesign_decomp.c
- **
- ** Copyright ©1998-1999 Apple Computer, Inc.
- ** All rights reserved.
- **
- ** You may incorporate this sample code into your applications without
- ** restriction, though the sample code has been provided "AS IS" and the
- ** responsibility for its operation is 100% yours. However, what you are
- ** not permitted to do is to redistribute the source as "Apple Sample
- ** Code" after having made changes. If you're going to re-distribute the
- ** source, we require that you make it clear in the source that the code
- ** was descended from Apple Sample Code, but that you've made changes.
- */
-
- #include <Memory.h>
- #include <QuickDraw.h>
- #include <Fonts.h>
- #include <Windows.h>
- #include <Menus.h>
- #include <TextEdit.h>
- #include <Dialogs.h>
- #include <Sound.h>
- #include <SoundInput.h>
- #include <Files.h>
- #include <Navigation.h>
-
- #include <stdio.h>
- #include "SoundStruct.h"
- #include "AIFF.h"
-
- typedef struct {
- long atomSize; // how big this structure is (big endian)
- long atomType; // atom type
- char waveData[28];
- } AtomQDMCWaveFormatEx;
-
- typedef struct {
- AudioFormatAtom formatData;
- AtomQDMCWaveFormatEx endianData;
- AudioTerminatorAtom terminatorData;
- } AudioCompressionAtom, *AudioCompressionAtomPtr, **AudioCompressionAtomHandle;
-
- // Prototypes
- OSErr InstallRequiredAppleEvents (void);
- pascal OSErr HandleOApp (AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon);
- pascal OSErr HandleODoc (AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon);
- pascal OSErr HandlePDoc (AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon);
- pascal OSErr HandleQuit (AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon);
- OSErr GetSoundToPlay (FSSpec *fileToPlay);
- OSErr PlaySound (FSSpec *fileToPlay);
-
- // Globals
- Boolean gBufferDone = false,
- gDone = false;
-
- static pascal void SoundCallBackFcn (SndChannelPtr theChannel, SndCommand *theCmd) {
- #pragma unused (theChannel)
- #if !GENERATINGCFM
- long oldA5;
- oldA5 = SetA5 (theCmd->param2);
- #endif
-
- gBufferDone = true;
-
- #if !GENERATINGCFM
- oldA5 = SetA5 (oldA5);
- #endif
- }
-
- static OSErr MenuBarInit (void) {
- Handle menuBar;
- MenuHandle menu;
- OSErr err = noErr;
-
- menuBar = GetNewMBar (128);
- if (menuBar != nil) {
- SetMenuBar (menuBar);
- menu = GetMenuHandle (128);
- if (menu != nil) {
- AppendResMenu (menu, 'DRVR');
- DrawMenuBar ();
- } else {
- err = memFullErr;
- }
- } else {
- err = memFullErr;
- }
-
- return err;
- }
-
- static OSErr DispatchMenuChoice (long menuChoice) {
- OSErr err = noErr;
- short menu;
- short item;
- MenuHandle appleMenu;
- Str255 accName;
- short accNumber;
- FSSpec fileToPlay;
-
- if (menuChoice != 0) {
- menu = HiWord (menuChoice);
- item = LoWord (menuChoice);
- switch (menu) {
- case 128: // Apple Menu
- appleMenu = GetMenuHandle (128);
- GetMenuItemText (appleMenu, item, accName);
- accNumber = OpenDeskAcc (accName);
- break;
- case 129: // File Menu
- switch (item) {
- case 1: // Open
- err = GetSoundToPlay (&fileToPlay);
- break;
- case 3: // Quit
- gDone = true;
- break;
- }
- }
- }
-
- HiliteMenu (0);
-
- return err;
- }
-
- void main (void) {
- OSErr err = noErr;
- Boolean gotEvent;
- EventRecord event;
- WindowPtr window;
- short thePart;
-
- MaxApplZone ();
-
- InitGraf (&qd.thePort);
- InitFonts ();
- InitWindows ();
- InitMenus ();
- TEInit ();
- InitDialogs ((long)nil);
- InitCursor ();
-
- err = InstallRequiredAppleEvents ();
-
- err = MenuBarInit ();
-
- while (!gDone) {
- gotEvent = WaitNextEvent (everyEvent, &event, 10, nil);
-
- if (gotEvent) {
- switch (event.what) {
- case kHighLevelEvent:
- err = AEProcessAppleEvent (&event);
- break;
- case mouseDown:
- thePart = FindWindow (event.where, &window);
- switch (thePart) {
- case inMenuBar:
- DispatchMenuChoice (MenuSelect (event.where));
- break;
- }
- break;
- case keyDown:
- if (event.modifiers & cmdKey) {
- err = DispatchMenuChoice (MenuKey (event.message & charCodeMask));
- }
- break;
- }
- }
- }
- }
-
- OSErr GetSoundToPlay (FSSpec *fileToPlay) {
- OSErr err = noErr;
- SFTypeList typeList = {'AIFF', 'AIFC', 0, 0};
- StandardFileReply sfReply;
-
- if (NavServicesAvailable () == true) {
- NavReplyRecord navReply;
- NavDialogOptions dialogOptions;
-
- err = NavGetDefaultDialogOptions (&dialogOptions);
- if (err == noErr) {
- dialogOptions.dialogOptionFlags = kNavAllFilesInPopup;
- }
-
- if (err == noErr) {
- err = NavGetFile (nil, &navReply, &dialogOptions, nil, nil, nil, nil, nil);
- }
-
- if (navReply.validRecord && err == noErr) {
- ProcessSerialNumber processSN = {0, kCurrentProcess};
- AEAddressDesc targetAddress = {typeNull, nil};
- AppleEvent theODOC = {typeNull, nil},
- theReply = {typeNull, nil};
-
- // Create an Apple Event to ourselves.
- err = AECreateDesc (typeProcessSerialNumber, &processSN, sizeof (ProcessSerialNumber), &targetAddress);
-
- if (err == noErr) {
- // Create the open document event.
- err = AECreateAppleEvent (kCoreEventClass, kAEOpenDocuments, &targetAddress, kAutoGenerateReturnID, kAnyTransactionID, &theODOC);
- AEDisposeDesc (&targetAddress);
- }
-
- if (err == noErr) {
- // Put the list of files into the open document event Apple Event.
- err = AEPutParamDesc (&theODOC, keyDirectObject, &(navReply.selection));
- }
-
- if (err == noErr) {
- // Send the open document event to ourselves.
- err = AESend (&theODOC, &theReply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, nil, nil);
- AEDisposeDesc (&theODOC);
- AEDisposeDesc (&theReply);
- }
-
- }
-
- (void)NavDisposeReply (&navReply);
- } else {
- StandardGetFile (nil, 2, typeList, &sfReply);
-
- if (sfReply.sfGood == true) {
- *fileToPlay = sfReply.sfFile;
- err = PlaySound (fileToPlay);
- } else {
- err = userCanceledErr;
- }
- }
-
- return err;
- }
-
- OSErr PlaySound (FSSpec *fileToPlay) {
- OSErr err = noErr;
- SoundInfo theSoundInfo;
- SndChannelPtr soundChan = nil;
- AudioCompressionAtom decomAtom;
- SoundComponentData inputFormat,
- outputFormat;
- SndCallBackUPP SoundCallBackFcnUPP = nil;
- CmpSoundHeader AIFFSndHeader1,
- AIFFSndHeader2;
- CmpSoundHeaderPtr AIFFSndHeader = nil;
- short whichBuffer = 0;
- SndCommand playCmd1,
- playCmd2,
- callCmd;
- SndCommand* playCmd = nil;
- SoundConverter sc = nil;
- Ptr decomBuf1 = nil,
- decomBuf2 = nil,
- AIFFBuffer = nil,
- compressedBuf = nil,
- decomBuf = nil;
- long length = 0;
- unsigned long inputFrames = 0,
- inputBytes = 0,
- outputFrames = 0,
- outputBytes = 0,
- bytesConverted = 0,
- targetBytes = 32768;
- Boolean soundDone = false;
-
- if (err == noErr) {
- err = FSpOpenDF (fileToPlay, fsRdPerm, &theSoundInfo.refNum);
-
- if (err == noErr) {
- err = ASoundGetAIFFHeader (&theSoundInfo, &length, &(decomAtom.formatData));
- }
-
- if (err == noErr) {
- inputFormat.flags = 0;
- inputFormat.format = decomAtom.formatData.format;
- inputFormat.numChannels = theSoundInfo.doubleHeader.dbhNumChannels;
- inputFormat.sampleSize = theSoundInfo.doubleHeader.dbhSampleSize;
- inputFormat.sampleRate = theSoundInfo.doubleHeader.dbhSampleRate;
- inputFormat.sampleCount = 0;
- inputFormat.buffer = nil;
- inputFormat.reserved = 0;
-
- outputFormat.flags = 0;
- outputFormat.format = kSoundNotCompressed;
- outputFormat.numChannels = inputFormat.numChannels;
- outputFormat.sampleSize = inputFormat.sampleSize;
- outputFormat.sampleRate = inputFormat.sampleRate;
- outputFormat.sampleCount = 0;
- outputFormat.buffer = nil;
- outputFormat.reserved = 0;
-
- err = SoundConverterOpen (&inputFormat, &outputFormat, &sc);
- }
-
- if (err == noErr) {
- err = SoundConverterSetInfo (sc, siDecompressionParams, &decomAtom);
- }
-
- if (err == noErr) {
- do {
- targetBytes *= 2;
- err = SoundConverterGetBufferSizes (sc, targetBytes, &inputFrames, &inputBytes, &outputBytes);
- } while (err == notEnoughBufferSpace && targetBytes < (MaxBlock () / 4));
- }
-
- if (err == noErr) {
- AIFFBuffer = NewPtr (length);
- err = MemError ();
- }
-
- if (err == noErr) {
- decomBuf1 = NewPtr (outputBytes);
- err = MemError ();
- }
-
- if (err == noErr) {
- decomBuf2 = NewPtr (outputBytes);
- err = MemError ();
- }
-
- if (err == noErr) {
- compressedBuf = NewPtr (inputBytes);
- err = MemError ();
- }
-
- if (err == noErr) {
- err = SetFPos (theSoundInfo.refNum, fsFromStart, theSoundInfo.dataStart);
- }
-
- if (err == noErr) {
- err = FSRead (theSoundInfo.refNum, &length, AIFFBuffer);
- }
-
- if (err == noErr) {
- BlockMoveData (AIFFBuffer, compressedBuf, inputBytes);
- err = SoundConverterBeginConversion (sc);
- }
-
- if (err == noErr) {
- bytesConverted = 0;
- err = SoundConverterConvertBuffer (sc, compressedBuf, inputFrames, decomBuf1, &outputFrames, &outputBytes);
- bytesConverted += inputBytes;
- }
-
- if (err == noErr) {
- if (bytesConverted + inputBytes > length) {
- inputBytes = length - bytesConverted;
- }
- BlockMoveData (AIFFBuffer + bytesConverted, compressedBuf, inputBytes);
- err = SoundConverterConvertBuffer (sc, compressedBuf, inputFrames, decomBuf2, &outputFrames, &outputBytes);
- bytesConverted += inputBytes;
- }
-
- if (err == noErr) {
- SoundCallBackFcnUPP = NewSndCallBackProc (SoundCallBackFcn);
- err = SndNewChannel (&soundChan, sampledSynth, 0, SoundCallBackFcnUPP);
- }
-
- if (err == noErr) {
- AIFFSndHeader1.samplePtr = decomBuf1;
- AIFFSndHeader1.numChannels = outputFormat.numChannels;
- AIFFSndHeader1.sampleRate = outputFormat.sampleRate;
- AIFFSndHeader1.loopStart = 0;
- AIFFSndHeader1.loopEnd = 0;
- AIFFSndHeader1.encode = cmpSH;
- AIFFSndHeader1.baseFrequency = kMiddleC;
- AIFFSndHeader1.numFrames = outputFrames;
- AIFFSndHeader1.AIFFSampleRate = 0; // not used
- AIFFSndHeader1.markerChunk = nil;
- AIFFSndHeader1.format = outputFormat.format;
- AIFFSndHeader1.futureUse2 = 0;
- AIFFSndHeader1.stateVars = nil;
- AIFFSndHeader1.leftOverSamples = nil;
- AIFFSndHeader1.compressionID = fixedCompression; // even uncompressed sounds use fixedCompression
- AIFFSndHeader1.packetSize = 0; // the Sound Manager will figure this out for us
- AIFFSndHeader1.snthID = 0;
- AIFFSndHeader1.sampleSize = outputFormat.sampleSize;
- AIFFSndHeader1.sampleArea[0] = 0; // no samples here because use samplePtr instead
-
- BlockMoveData (&AIFFSndHeader1, &AIFFSndHeader2, sizeof (AIFFSndHeader1));
- AIFFSndHeader2.samplePtr = decomBuf2;
-
- playCmd1.cmd = bufferCmd;
- playCmd1.param1 = 0; // not used, but clear it out anyway just to be safe
- playCmd1.param2 = (long)&AIFFSndHeader1;
-
- playCmd2.cmd = bufferCmd;
- playCmd2.param1 = 0; // not used, but clear it out anyway just to be safe
- playCmd2.param2 = (long)&AIFFSndHeader2;
-
- whichBuffer = 1; // buffer 1 will be free when callback runs
- callCmd.cmd = callBackCmd;
- callCmd.param2 = SetCurrentA5 ();
-
- soundDone = false;
- gBufferDone = false;
- err = SndDoCommand (soundChan, &playCmd1, true);
- }
-
- if (err == noErr) {
- err = SndDoCommand (soundChan, &callCmd, true);
- }
-
- if (err == noErr) {
- err = SndDoCommand (soundChan, &playCmd2, true);
- }
-
- if (err == noErr) {
- while (!soundDone) {
- if (gBufferDone == true) {
- if (whichBuffer == 1) {
- playCmd = &playCmd1;
- decomBuf = decomBuf1;
- AIFFSndHeader = &AIFFSndHeader1;
- whichBuffer = 2;
- } else {
- playCmd = &playCmd2;
- decomBuf = decomBuf2;
- AIFFSndHeader = &AIFFSndHeader2;
- whichBuffer = 1;
- }
-
- if (bytesConverted < length) {
- if (bytesConverted + inputBytes > length) {
- inputBytes = length - bytesConverted;
- }
-
- BlockMoveData (AIFFBuffer + bytesConverted, compressedBuf, inputBytes);
-
- (void)SoundConverterConvertBuffer (sc, compressedBuf, inputFrames, decomBuf, &outputFrames, &outputBytes);
- bytesConverted += inputBytes;
- AIFFSndHeader->numFrames = outputFrames;
-
- gBufferDone = false;
- (void)SndDoCommand (soundChan, &callCmd, true); // Reuse callBackCmd.
- (void)SndDoCommand (soundChan, playCmd, true); // Play the next buffer.
- } else {
- (void)SoundConverterEndConversion (sc, decomBuf, &outputFrames, &outputBytes);
- AIFFSndHeader->numFrames = outputFrames;
-
- (void)SndDoCommand (soundChan, playCmd, true); // Play the last buffer.
- soundDone = true;
- }
- }
- }
- }
-
- if (sc != nil) {
- err = SoundConverterClose (sc);
- }
-
- if (err == noErr) {
- err = SndDisposeChannel (soundChan, false); // wait until sounds stops playing before disposing of channel
- }
-
- if (theSoundInfo.refNum)
- FSClose (theSoundInfo.refNum);
- if (SoundCallBackFcnUPP)
- DisposeRoutineDescriptor (SoundCallBackFcnUPP);
- if (decomBuf1)
- DisposePtr (decomBuf1);
- if (decomBuf2)
- DisposePtr (decomBuf2);
- if (AIFFBuffer)
- DisposePtr (AIFFBuffer);
- if (compressedBuf)
- DisposePtr (compressedBuf);
- }
-
- return err;
- }
-
- OSErr InstallRequiredAppleEvents (void) {
- OSErr err;
-
- err = AEInstallEventHandler (kCoreEventClass, kAEOpenApplication, NewAEEventHandlerProc (HandleOApp), 0, false);
-
- if (err == noErr)
- err = AEInstallEventHandler (kCoreEventClass, kAEOpenDocuments, NewAEEventHandlerProc (HandleODoc), 0, false);
-
- if (err == noErr)
- err = AEInstallEventHandler (kCoreEventClass, kAEPrintDocuments, NewAEEventHandlerProc (HandlePDoc), 0, false);
-
- if (err == noErr)
- err = AEInstallEventHandler (kCoreEventClass, kAEQuitApplication, NewAEEventHandlerProc (HandleQuit), 0, false);
-
- return err;
- }
-
- pascal OSErr HandleOApp (AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon) {
- #pragma unused (theAppleEvent, reply, handlerRefcon)
-
- return noErr; /* We're up and running */
- }
-
- pascal OSErr HandleODoc (AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon) {
- #pragma unused (reply, handlerRefcon)
-
- AEDescList docList;
- OSErr err;
- long i = 1,
- itemsInList;
- Size actualSize;
- AEKeyword keywd;
- DescType returnedType;
-
- err = AEGetParamDesc (theAppleEvent, keyDirectObject, typeAEList, &docList);
- if (err == noErr) {
- err = AECountItems (&docList, &itemsInList);
- }
-
- if (err == noErr) {
- FSSpecPtr fileSpecPtr;
-
- do {
- fileSpecPtr = (FSSpecPtr)NewPtr (sizeof (FSSpec));
- err = MemError ();
-
- if (err == noErr) {
- err = AEGetNthPtr (&docList, i, typeFSS, &keywd, &returnedType, fileSpecPtr, sizeof (FSSpec), &actualSize);
- }
-
- if (err == noErr) {
- HParamBlockRec pb;
-
- pb.fileParam.ioCompletion = nil;
- pb.fileParam.ioNamePtr = fileSpecPtr->name;
- pb.fileParam.ioVRefNum = fileSpecPtr->vRefNum;
- pb.fileParam.ioDirID = fileSpecPtr->parID;
- pb.fileParam.ioFDirIndex = 0;
-
- err = PBHGetFInfoSync (&pb);
- if (err == noErr && pb.fileParam.ioFlFndrInfo.fdType != 'pref') {
- err = PlaySound (fileSpecPtr);
- DisposePtr ((Ptr)fileSpecPtr);
- }
- }
-
- i += 1;
- } while (err == noErr);
-
- // The last time through the loop we allocate a pointer we don't need.
- DisposePtr ((Ptr)fileSpecPtr);
- }
-
- (void)AEDisposeDesc (&docList);
-
- return err;
- }
-
- pascal OSErr HandlePDoc (AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon) {
- #pragma unused (theAppleEvent, reply, handlerRefcon)
-
- return noErr;
- }
-
- pascal OSErr HandleQuit (AppleEvent *theAppleEvent, AppleEvent *reply, long handlerRefcon) {
- #pragma unused (theAppleEvent, reply, handlerRefcon)
-
- gDone = true;
- return noErr;
- }
-